上一篇講到uniform distribution,使用一個random function讓每一個事件發生的機率都相同。但實際上在自然環境中,很少出現如此平均的情況,大部份的情況都是non-uniform distribution,書中用達爾文的進化論舉例,在同一個猴子族群中,不是每一隻猴子都能夠有相同的機會繁殖下一代,強壯的猴子通常比瘦弱的猴子有較大的機會。
那要怎麼樣用程式實作出non-uniform distribution? 同樣利用random() function,只要稍微修改一下就可以了,在實作之前要先來了解機率是什麼
,機率簡單的說就是 將“指定的事件可能發生的情況”除以“所有情況”,舉例來說投擲一枚硬幣,得到正面的機率是50%,正面的情況/所有情況(正面+反面)。
在一副撲克牌中,抽到A(aces)的機率是:
A的數目/撲克牌的數目 = 4/52 = 0.077 =~ 8%
抽到磚塊(Diamond)的機率是:
磚塊數目/撲克牌數目 = 13/52 = 0.25 = 25%
也可以計算多個連續事件的機率,將所有單一事件的機率相乘就可以了,比如連續擲三次骰子都得到正面的機率是
(1/2) * (1/2) * (1/2) = 1/8 (or 0.125)
回到要怎麼用程式模擬機率這件事,可以使用Array,將機率較高的事件在Array中重複。
int[] stuff = new int[5]
stuff[0] = 1;
stuff[1] = 1;
stuff[2] = 2;
stuff[3] = 3;
stuff[4] = 3;
int index = int(random(stuff.length));
我們選到Array中每一個index的機率是相同的,都是20%(1/5),但是因為每一個元素填寫的數值可以重複,因此我們stuff[index]選到的數值就可以造成不同的機率,比如說選到1的機率是5分之2,因為1在array中出現兩次。
或者也可以換成另一種寫法:
float prob = 0.10;
float r = random(1);
if (r < prob) {
// try again!
}
因為random(1)會產生0~1之間的浮點數結果,因此小於0.10的機率是10%,大於等於0.10則是90%
這種方法也可以用在多個結果的事件:
float num = random(1);
if (num < 0.6) {
println("Outcome A");
} else if (num < 0.7) {
println("Outcome B");
} else {
println("Outcome C");
}
0.0~0.6的機率為60%
0.6~0.7的機率為70%
0.7~1.0的機率為30%
用了以上方法就可以來模擬non-uniform distribution囉,再拿出random walker來使用,假如要讓random walker偏向右邊行走,計劃如下:
向上走的機率 20%
向下走的機率 20%
向右走的機率 40%
向左走的機率 20%
void step() {
float r = random(1);
if (r < 0.4) {
x++;
} else if (r < 0.6) {
x--;
} else if (r < 0.8) {
y++;
} else {
y--;
}
}
結果在此~http://natureofcode.com/book/introduction/#canvas2
這一節書上有提供一個練習:
將random walker改造成,有50%的機率往滑鼠的方向移動。
我是這樣做的:
void step() {
float choice = random(1);
if(choice < 0.12){
x++;
}else if(choice < 0.24){
x--;
}else if(choice < 0.36){
y++;
}else if(choice < 0.5){
y--;
}else{
int offsetX = mouseX-x;
int offsetY = mouseY-y;
if( offsetX > 0){
x++;
}else{
x--;
}
if( offsetY > 0){
y++;
}else{
y--;
}
}
}
下一篇介紹Normal Distribution。